#include "Core/VecMath.h"

namespace Orca {

	//--------------------------------------------------------------------------
	vec3 toVec3(const vec2 &xy, float z) {
		return vec3(xy[0], xy[1], z);
	}

	//--------------------------------------------------------------------------
	vec3 toVec3(const vec4 &v) {
		return vec3(v[0], v[1], v[2]);
	}

	//--------------------------------------------------------------------------
	vec4 toVec4(const vec4 &xy, float z, float w) {
		return vec4(xy[0], xy[1], z, w);
	}

	//--------------------------------------------------------------------------
	vec4 toVec4(const vec3 &xyz, float w) {
		return vec4(xyz[0], xyz[1], xyz[2], w);
	}

	//--------------------------------------------------------------------------
	mtx22 identity2() {

		mtx22 out;
		identity(out);

		return out;
	}

	//--------------------------------------------------------------------------
	mtx33 identity3() {

		mtx33 out;
		identity(out);

		return out;

	}

	//--------------------------------------------------------------------------
	mtx44 identity4() {

		mtx44 out;
		identity(out);

		return out;

	}

	//--------------------------------------------------------------------------
	mtx33 get3x3(const mtx44 &mtx4) {

		mtx33 out;

		out.set(
			mtx4[0][0], mtx4[0][1], mtx4[0][2],
			mtx4[1][0], mtx4[1][1], mtx4[1][2],
			mtx4[2][0], mtx4[2][1], mtx4[2][2] );

		return out;
	}

	//--------------------------------------------------------------------------
	mtx22 rotate(const float angle)
	{
		float cosA = cosf(angle), sinA = sinf(angle);

		mtx22 out;
		out.set(cosA, -sinA, sinA, cosA);

		return out;
	}

	//--------------------------------------------------------------------------
	mtx44 rotateX(const float angle)
	{
		float cosA = cosf(angle), sinA = sinf(angle);

		mtx44 out;

		out.set(
			1, 0,     0,    0,
			0, cosA, -sinA, 0,
			0, sinA,  cosA, 0,
			0, 0,     0,    1);

		return out;
	}

	//--------------------------------------------------------------------------
	mtx44 rotateY(const float angle)
	{
		float cosA = cosf(angle), sinA = sinf(angle);

		mtx44 out;

		out.set(
			cosA, 0, -sinA, 0,
			0,    1,  0,    0,
			sinA, 0,  cosA, 0,
			0,    0,  0,    1);

		return out;
	}

	//--------------------------------------------------------------------------
	mtx44 rotateZ(const float angle)
	{
		float cosA = cosf(angle), sinA = sinf(angle);

		mtx44 out;

		out.set(
			cosA, -sinA, 0, 0,
			sinA,  cosA, 0, 0,
			0,     0,    1, 0,
			0,     0,    0, 1);

		return out;
	}

	//--------------------------------------------------------------------------
	mtx44 rotateXY(const float angleX, const float angleY)
	{
		float cosX = cosf(angleX), sinX = sinf(angleX), 
			cosY = cosf(angleY), sinY = sinf(angleY);

		mtx44 out;

		out.set(
			cosY,        0,    -sinY,        0,
			-sinX * sinY, cosX, -sinX * cosY, 0,
			cosX * sinY, sinX,  cosX * cosY, 0,
			0,           0,     0,           1);

		return out;
	}

	//--------------------------------------------------------------------------
	mtx44 rotateYX(const float angleX, const float angleY)
	{
		float cosX = cosf(angleX), sinX = sinf(angleX), 
			cosY = cosf(angleY), sinY = sinf(angleY);

		mtx44 out;

		out.set(
			cosY, -sinX * sinY, -cosX * sinY, 0,
			0,     cosX,        -sinX,        0,
			sinY,  sinX * cosY,  cosX * cosY, 0,
			0,     0,            0,           1);

		return out;
	}

	//--------------------------------------------------------------------------
	mtx44 rotateZXY(const float angleX, const float angleY, const float angleZ)
	{
		float cosX = cosf(angleX), sinX = sinf(angleX), 
			cosY = cosf(angleY), sinY = sinf(angleY),
			cosZ = cosf(angleZ), sinZ = sinf(angleZ);

		mtx44 out;

		out.set(
			cosY * cosZ + sinX * sinY * sinZ,   -cosX * sinZ,    sinX * cosY * sinZ - sinY * cosZ,  0,
			cosY * sinZ - sinX * sinY * cosZ,    cosX * cosZ,   -sinY * sinZ - sinX * cosY * cosZ,  0,
			cosX * sinY,                         sinX,           cosX * cosY,                       0,
			0,                                   0,              0,                                 1);

		return out;
	}

	//--------------------------------------------------------------------------
	mtx44 translate(const vec3 &v)
	{
		mtx44 out;
		out.set(1,0,0,v[0], 0,1,0,v[1], 0,0,1,v[2], 0,0,0,1);

		return out;
	}

	//--------------------------------------------------------------------------
	mtx44 translate(const float x, const float y, const float z)
	{
		mtx44 out;
		out.set(1,0,0,x, 0,1,0,y, 0,0,1,z, 0,0,0,1);

		return out;
	}

	//--------------------------------------------------------------------------
	mtx44 scale(const float x, const float y, const float z)
	{
		mtx44 out;
		out.set(x,0,0,0, 0,y,0,0, 0,0,z,0, 0,0,0,1);

		return out;
	}

	
	//--------------------------------------------------------------------------
	mtx44 cubeViewMatrix(CubeMapSide side)
	{
		mtx44 out;

		switch(side)
		{
		case CUBE_POSITIVE_X:
			out.set(
				0, 0, -1, 0,
				0, 1,  0, 0,
				1, 0,  0, 0,
				0, 0,  0, 1);
			break;
		case CUBE_NEGATIVE_X:
			out.set(
				0, 0, 1, 0,
				0, 1, 0, 0,
				-1, 0, 0, 0,
				0, 0, 0, 1);
			break;
		case CUBE_POSITIVE_Y:
			out.set(
				1, 0,  0, 0,
				0, 0, -1, 0,
				0, 1,  0, 0,
				0, 0,  0, 1);
			break;
		case CUBE_NEGATIVE_Y:
			out.set(
				1,  0, 0, 0,
				0,  0, 1, 0,
				0, -1, 0, 0,
				0,  0, 0, 1);
			break;
		case CUBE_POSITIVE_Z:
			out.set(
				1, 0, 0, 0,
				0, 1, 0, 0,
				0, 0, 1, 0,
				0, 0, 0, 1);
			break;
			//case NEGATIVE_Z:
		default:
			out.set(
				-1, 0,  0, 0,
				0, 1,  0, 0,
				0, 0, -1, 0,
				0, 0,  0, 1);
			break;
		}

		return out;
	}

	//--------------------------------------------------------------------------

}